home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / pascal / turbig.zip / TURBIG.PAS
Pascal/Delphi Source File  |  1985-09-28  |  24KB  |  639 lines

  1. {
  2. BigTurbo - Turbo Pascal large Code model support
  3.  
  4.    **** FOR IBM PC And MSDOS machines only ****
  5.    **** Requires Turbo Pascal version 3.X  ****
  6.  
  7. This file concatenates 8 files that should be separated
  8. after download. The 8 files are as follows:
  9.  
  10.   BIGTUR.DOC - describes the BigTurbo system
  11.  
  12.   MAIN1.INC - include files for extra segment control
  13.   MAIN2.INC
  14.   FAR1.INC
  15.   FAR2.INC
  16.  
  17.   MAINEXAM.PAS - main code segment example
  18.   FAREXAM.PAS - far code segment example
  19.   EXAM.GLO - shared global data declarations for example
  20. }
  21.  
  22. {****************************************************************************}
  23. {FOLLOWING IS BIGTUR.DOC}
  24.  
  25.  ********************************************************************
  26.  * BigTurbo - copyright (c) 1985 Kim Kokkonen, TurboPower Software. *
  27.  ********************************************************************
  28.  *      written 9/85. (408)-378-3672. Compuserve 72457,2131.        *
  29.  *     This version is a prototype for a commercial product.        *
  30.  *    It is hereby released to the public domain for personal,      *
  31.  *                   non-commercial use only.                       *
  32.  *               We will appreciate any feedback.                   *
  33.  ********************************************************************
  34.  
  35.  The BigTurbo system provides control to set up an extra 64K code
  36.  segment for Turbo Pascal programs. It provides an alternative to
  37.  overlays and chaining with some advantages over either technique.
  38.  
  39.  The extra 64K code segment is written and compiled as a separate program
  40.  from the main code segment. The main block of the separate segment is
  41.  never used, unless you want to execute the program independently for
  42.  debug purposes. BigTurbo allows you to call the global procedures in the
  43.  extra code segment directly from the main program, or from procedures
  44.  in the main program. It also allows procedures in the extra code segment
  45.  to call each other and to call global procedures in the main code segment.
  46.  The two code segments share a common data segment, heap and stack, and
  47.  communication between the two segments is via global variables
  48.  (parameters are not allowed at present).
  49.  
  50.  BigTurbo requires files MAIN1.INC and MAIN2.INC to be included and
  51.  compiled with the main program, and the files FAR1.INC and FAR2.INC to
  52.  be included and compiled with the code comprising the extra code segment.
  53.  As described below, the programmer must make minor modifications to
  54.  the include files MAIN2.INC and FAR2.INC to make them work in his/her
  55.  program.
  56.  
  57.  The main program must have heap space reserved for the extra code
  58.  segment when it is compiled to a .COM file (the extra code segment
  59.  is loaded onto the heap of the main program). The extra code must be
  60.  compiled to a .COM file prior to executing the main program. The
  61.  code space, data space and heap/stack space options for the extra
  62.  code segment are never accessed and are therefore arbitrary.
  63.  
  64.  Hereafter, we will call the extra code segment the "Far" code segment.
  65.  
  66.  Communication between the Main code segment and the Far code segment
  67.  occurs only via global variables, similar to how Chain files are used.
  68.  As a result the Far program should contain a set of global data definitions
  69.  identical to those of the Main code segment. This is best managed by
  70.  putting the global definitions in an include file, and including that
  71.  file in both the Main and Far programs.
  72.  
  73.  Improvements of BigTurbo over using Chain files or Overlays are as follows:
  74.  
  75.   1) The Far code segment is loaded into memory only once, and remains
  76.      there until the program completes. You get a full extra 64K segment
  77.      (less runtime library overhead, about 10K) to use.
  78.  
  79.   2) Any global procedure in the Far code segment may be called directly
  80.      either from the main code segment or from within the Far code
  81.      segment.
  82.  
  83.   3) Any global procedure in the Main code segment may be called directly
  84.      either from the Far code segment or from within the main code
  85.      segment (as usual).
  86.  
  87.   4) Upon completion of a call to the Far code segment, control returns
  88.      to the calling procedure. Calls in the other direction work the
  89.      same way.
  90.  
  91.   5) The Main and Far code share the same heap and data segment, which
  92.      provides adequate means of communication between the two.
  93.  
  94.   6) The restrictions on what can call what are fewer than for overlays.
  95.  
  96.   7) You can do the equivalent of overlays by DISPOSing of the code
  97.      on the heap and loading another file's worth of code there. Only
  98.      one extra code segment is allowed at a time, although the techniques
  99.      here can clearly be extended to more segments with some logistic
  100.      headaches.
  101.  
  102.   8) These techniques are not specific to any particular version of
  103.      Turbo, although we have assumed version 3.X (of any flavor).
  104.  
  105.  
  106.  Limitations of BigTurbo are as follows:
  107.  
  108.   1) For now, calls across the code segment boundary may not use
  109.      parameters, and must be made only to procedures (not functions).
  110.  
  111.   2) The programmer must do a small amount of manual management to keep
  112.      the required addressing tables set up (see SetupJumpTable below).
  113.  
  114.   3) An extra copy of the Turbo runtime library is loaded into
  115.      memory for the Far code segment. This costs about 10K bytes of
  116.      RAM.
  117.  
  118.   4) The Far code may not use global variables that are not used in the
  119.      Main code segment, and vice versa. The order of the global variable
  120.      definitions must be identical in each to guarantee proper addressing,
  121.      just as with chain files.
  122.  
  123.   5) The Far code should not use EXTERNAL procedures or INLINE code that
  124.      enters and exits the global procedures in any way but the Turbo Pascal
  125.      standard.
  126.  
  127.   6) Stack checking is not currently implemented for Far calls. Such
  128.      checking once implemented will be compiler version specific.
  129.  
  130.   7) Far calls are somewhat slower than near calls (see the code in
  131.      FarCallHandler and MainCallHandler to judge the overhead).
  132.  
  133.   8) As with Turbo overlays, runtime errors will provide misleading
  134.      addresses when they occur in the Far segment.
  135.  
  136.   9) This hasn't been tested with overlays used being simultaneously, and
  137.      we have a feeling it wouldn't work well.
  138.  
  139.  Other Comments:
  140.  
  141.   1) The procedures in the Far code segment may contain subprocedures,
  142.      local variables, and typed constants just as usual. Calls to the
  143.      subprocedures may use parameters as usual. A Far procedure may
  144.      call itself recursively if desired.
  145.  
  146.   2) The main executable block of the Far program may be empty. It will
  147.      never be accessed, unless you are using it to debug the Far procedures
  148.      independently.
  149.  
  150.   3) The Far code is loaded into a location on the heap of the Main program.
  151.      You need to reserve this amount of memory when you compile the
  152.      Main program.
  153.  
  154.   4) Your program should use the {$V-} directive to avoid problems in
  155.      string length type checking with these routines.
  156.  
  157.   5) MAIN1.INC and MAIN2.INC add about 1800 bytes of code to the main
  158.      segment. FAR1.INC and FAR2.INC add about 700 bytes of code to
  159.      the far segment.
  160.  
  161.  *******************************************************
  162.  *              See the example files                  *
  163.  *                  MAINEXAM.PAS                       *
  164.  *                  FAREXAM.PAS                        *
  165.  *                    EXAM.GLO                         *
  166.  *   for proper usage of the following include files   *
  167.  *******************************************************
  168.  
  169. {END OF BIGTUR.DOC}
  170. {****************************************************************************}
  171. {FOLLOWING IS MAIN1.INC}
  172.  
  173.   CONST
  174.     {set these values based on the size of the MAIN program}
  175.     MaxNumProcs = 10;         {maximum number of procedures available for Far calls}
  176.     MaxProcNameLength = 20;   {maximum name length of such procedures}
  177.  
  178.   TYPE
  179.     ProcNameArray = ARRAY[1..MaxNumProcs] OF STRING[MaxProcNameLength];
  180.     ProcOffsetArray = ARRAY[1..MaxNumProcs] OF Integer;
  181.     BigTurboString = STRING[64];
  182.     JumpRecord = RECORD
  183.                    offset, segment : Integer;
  184.                  END;
  185.  
  186.   CONST
  187.     {these need to be adjusted based on the value in MaxNumProcs}
  188.     {no literal values need be filled in here}
  189.     pnames : ProcNameArray = ('', '', '', '', '', '', '', '', '', '');
  190.     poffsets : ProcOffsetArray = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  191.  
  192.   VAR
  193.     FarCodePtr : ^integer;    {will hold pointer to where far code is stored}
  194.     MainHand : JumpRecord;    {holds pointer to MainCallHandler in this code segment}
  195.     FarJumpSet : JumpRecord;  {holds pointer to SetupJumpTable in Far code segment}
  196.     FarHand : JumpRecord;     {holds pointer to FarCallHandler in Far code segment}
  197.  
  198.   PROCEDURE MakeLongCall(FarProcName : BigTurboString);
  199.       {-pass control to the call handler in the Far code}
  200.     BEGIN
  201.       INLINE(
  202.         $8C/$D0/              {MOV    AX,SS}
  203.         $8E/$C0/              {MOV    ES,AX}
  204.         $8B/$F5/              {MOV    SI,BP}
  205.         $81/$C6/$04/$00/      {ADD    SI,0004}
  206.         $FF/$1E/FarHand       {CALL   FAR FarHand}
  207.         );
  208.     END;                      {MakeLongCall}
  209.  
  210. {END OF MAIN1.INC}
  211. {****************************************************************************}
  212. {FOLLOWING IS MAIN2.INC}
  213.  
  214.   PROCEDURE SetupJumpTable;
  215.       {-initialize the names and offsets of the near procedures}
  216.       {
  217.       ***************************************************
  218.       * The programmer must maintain the lists below to *
  219.       * include all global procedure names that will be *
  220.       * called from the Far code segment.               *
  221.       ***************************************************
  222.       }
  223.     BEGIN
  224.       {
  225.       *** EXAMPLES and COMMENTS ********************************************
  226.       * Order is unimportant, except that procedures which are called most *
  227.       *  often from far segment should be first in list.                   *
  228.       * Case of the string is important. Must be same as string passed to  *
  229.       *  MakeLongCall (avoids overhead time of uppercasing every call).    *
  230.       * Fill in your own procedure names below.                            *
  231.       **********************************************************************
  232.       }
  233.       pnames[1] := 'mainproc1';
  234.       poffsets[1] := Ofs(mainproc1);
  235.       pnames[2] := 'mainproc2';
  236.       poffsets[2] := Ofs(mainproc2);
  237.     END;                      {SetupJumpTable}
  238.  
  239.   PROCEDURE MainCallHandler;
  240.       {-pick up control from a far call and transfer to near procedure}
  241.     VAR
  242.       i : Integer;
  243.       procofs : Integer;
  244.       procname : BigTurboString;
  245.     BEGIN
  246.       {get procname from the es:si pointer passed in}
  247.       INLINE(
  248.         $31/$C9/              {XOR    CX,CX}
  249.         $26/                  {ES:    }
  250.         $8A/$0C/              {MOV    CL,[SI]}
  251.         $FE/$C1/              {INC    CL}
  252.         $BF/procname/         {MOV    DI,ofs(procname)}
  253.         $FC/                  {CLD    }
  254.         {10B:}
  255.         $26/                  {ES:    }
  256.         $AC/                  {LODSB    }
  257.         $88/$03/              {MOV    [BP+DI],AL}
  258.         $47/                  {INC    DI}
  259.         $E2/$F9               {LOOP    010B}
  260.         );
  261.       {match against the stored procnames}
  262.       i := 0;
  263.       REPEAT
  264.         i := i+1;
  265.       UNTIL (i > MaxNumProcs) OR (pnames[i] = procname);
  266.       {error check}
  267.       IF i > MaxNumProcs THEN BEGIN
  268.         WriteLn(Con);
  269.         WriteLn(Con, 'Far procedure ', procname, ' not found....');
  270.         Halt;
  271.       END;
  272.       {check for stack space, later}
  273.       {assure stack aligned for parameter passing, later}
  274.       {call the procedure}
  275.       procofs := poffsets[i];
  276.       INLINE(
  277.         $C4/$46/< procofs/    {LES    AX,procofs[BP]}
  278.         $FF/$D0               {CALL    AX}
  279.         );
  280.  
  281.       {restore stack frame and FAR return}
  282.       INLINE(
  283.         $8B/$E5/              {mov sp,bp}
  284.         $5D/                  {pop bp}
  285.         $CB                   {ret far}
  286.         );
  287.     END;                      {MainCallHandler}
  288.  
  289.   PROCEDURE LoadFarCode(FarComFileName : BigTurboString);
  290.       {-load the FarComFile and set up the required addresses}
  291.     CONST
  292.       id1string : BigTurboString = 'FARCALLHANDLER FOLLOWS';
  293.       id2string : BigTurboString = 'SETJUMPTABLE FOLLOWS';
  294.     VAR
  295.       f : FILE;
  296.       len : Byte ABSOLUTE FarComFileName;
  297.       i : Integer;
  298.       size : Integer;
  299.       FarCodeSeg : Integer;
  300.       FarCodeOfs : Integer;
  301.       ext : STRING[4];
  302.       testlen : Byte;
  303.       teststring : BigTurboString;
  304.     BEGIN
  305.  
  306.       {assure it is a .COM file}
  307.       ext := Copy(FarComFileName, len-3, 4);
  308.       FOR i := 1 TO 4 DO ext[i] := UpCase(ext[i]);
  309.       IF ext <> '.COM' THEN BEGIN
  310.         WriteLn(Con);
  311.         WriteLn(Con, 'Far Code File must be a .COM file');
  312.         Halt;
  313.       END;
  314.  
  315.       {make sure it exists and open it}
  316.       Assign(f, FarComFileName);
  317.       {note we are using a block size of 1}
  318.       {$I-} Reset(f, 1);      {$I+}
  319.       IF IOResult <> 0 THEN BEGIN
  320.         WriteLn(Con);
  321.         WriteLn(Con, 'Far Code File not found....');
  322.         Halt;
  323.       END;
  324.  
  325.       {make sure there is something in it}
  326.       size := FileSize(f);
  327.       IF size = 0 THEN BEGIN
  328.         WriteLn(Con);
  329.         WriteLn(Con, 'Far Code File is empty....');
  330.         Halt;
  331.       END;
  332.  
  333.       {make sure there is space for it}
  334.       IF (size SHR 4) > (MaxAvail-32) THEN BEGIN
  335.         WriteLn(Con);
  336.         WriteLn(Con, 'Far Code too large to load on heap....');
  337.         Close(f);
  338.         Halt;
  339.       END;
  340.  
  341.       {allocate memory on heap}
  342.       GetMem(FarCodePtr, size+512);
  343.       {IMPORTANT: normalize seg and ofs so that we can make farcodeofs=$100}
  344.       FarCodeSeg := Seg(FarCodePtr);
  345.       FarCodeOfs := Ofs(FarCodePtr);
  346.       WHILE FarCodeOfs > $100 DO BEGIN
  347.         FarCodeOfs := FarCodeOfs-16;
  348.         FarCodeSeg := FarCodeSeg+1;
  349.       END;
  350.       FarCodePtr := Ptr(FarCodeSeg, $100);
  351.       FarCodeOfs := $100;
  352.  
  353.       {load code onto heap}
  354.       BlockRead(f, farcodeptr^, size);
  355.       Close(f);
  356.  
  357.       {store the pointers}
  358.       FarJumpSet.segment := FarCodeSeg;
  359.       FarHand.segment := FarCodeSeg;
  360.       {store the local addresses}
  361.       MainHand.offset := Ofs(MainCallHandler);
  362.       MainHand.segment := CSeg;
  363.  
  364.       {search the far code for the idstrings identifying key offsets}
  365.       {start at the top and work backwards, should be faster}
  366.       i := size;
  367.       testlen := Length(id1string)+1;
  368.       REPEAT
  369.         i := i-1;
  370.         Move(Mem[FarCodeSeg:(FarCodeOfs+i)], teststring, testlen);
  371.       UNTIL (i < 1) OR (teststring = id1string);
  372.       IF i < 1 THEN BEGIN
  373.         WriteLn(Con);
  374.         WriteLn(Con, 'ID string ', id1string, ' not found in Far code....');
  375.         Halt;
  376.       END;
  377.       {store the adjusted offset for far calls}
  378.       FarHand.offset := FarCodeOfs+i-7;
  379.  
  380.       testlen := Length(id2string)+1;
  381.       REPEAT
  382.         i := i-1;
  383.         Move(Mem[FarCodeSeg:(FarCodeOfs+i)], teststring, testlen);
  384.       UNTIL (i < 1) OR (teststring = id2string);
  385.       IF i < 1 THEN BEGIN
  386.         WriteLn(Con);
  387.         WriteLn(Con, 'ID string ', id2string, ' not found in Far code....');
  388.         Halt;
  389.       END;
  390.       {store the adjusted offset for far calls}
  391.       FarJumpSet.offset := FarCodeOfs+i-7;
  392.  
  393.       {set up the local jump table}
  394.       SetupJumpTable;
  395.  
  396.       {set up the far jump table}
  397.       INLINE(
  398.         $FF/$1E/FarJumpSet    {CALL    FAR FarJumpSet}
  399.         );
  400.       {we are done}
  401.     END;                      {LoadFarCode}
  402.  
  403. {END OF MAIN2.INC}
  404. {****************************************************************************}
  405. {FOLLOWING IS FAR1.INC}
  406.  
  407.   CONST
  408.     {set these values based on the size of the FAR program}
  409.     {see comments in MAIN1.INC}
  410.     MaxNumProcs = 10;
  411.     MaxProcNameLength = 20;
  412.   TYPE
  413.     ProcNameArray = ARRAY[1..MaxNumProcs] OF STRING[MaxProcNameLength];
  414.     ProcOffsetArray = ARRAY[1..MaxNumProcs] OF Integer;
  415.     BigTurboString = STRING[64];
  416.     JumpRecord = RECORD
  417.                    offset, segment : Integer;
  418.                  END;
  419.   CONST
  420.     {these need to be adjusted based on the value in MaxNumProcs}
  421.     {no literal values need be filled in here}
  422.     pnames : ProcNameArray = ('', '', '', '', '', '', '', '', '', '');
  423.     poffsets : ProcOffsetArray = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  424.   VAR
  425.     FarCodePtr : ^integer;    {will hold pointer to where far code is stored}
  426.     MainHand : JumpRecord;    {holds pointer to MainCallHandler in the other code segment}
  427.     FarJumpSet : JumpRecord;  {holds pointer to SetupJumpTable in this code segment}
  428.     FarHand : JumpRecord;     {holds pointer to FarCallHandler in this code segment}
  429.  
  430.   PROCEDURE MakeLongCall(FarProcName : BigTurboString);
  431.       {-pass control to the call handler in the Far code}
  432.     BEGIN
  433.       INLINE(
  434.         $8C/$D0/              {MOV    AX,SS}
  435.         $8E/$C0/              {MOV    ES,AX}
  436.         $8B/$F5/              {MOV    SI,BP}
  437.         $81/$C6/$04/$00/      {ADD    SI,0004}
  438.         $FF/$1E/MainHand      {CALL   FAR MainHand}
  439.         );
  440.     END;                      {MakeLongCall}
  441.  
  442. {END OF FAR1.INC}
  443. {****************************************************************************}
  444. {FOLLOWING IS FAR2.INC}
  445.  
  446.   PROCEDURE SetupJumpTable;
  447.       {-initialize the names and offsets of the near procedures}
  448.       {
  449.       ***************************************************
  450.       * The programmer must maintain the lists below to *
  451.       * include all global procedure names that may be  *
  452.       * called from the MAIN code segment.              *
  453.       * This procedure should never be called directly  *
  454.       * within its own program.                         *
  455.       ***************************************************
  456.       }
  457.     CONST
  458.       {following string must be here to allow address to be found from Main Code}
  459.       idstring : BigTurboString = 'SETJUMPTABLE FOLLOWS';
  460.     BEGIN
  461.       {
  462.       *** EXAMPLES and COMMENTS ********************************************
  463.       * Order is unimportant, except that procedures which are called most *
  464.       *  often from far segment should be first in list.                   *
  465.       * Case of the string is important. Must be same as string passed to  *
  466.       *  MakeLongCall (avoids overhead time of uppercasing every call).    *
  467.       * Fill in your own procedure names below.                            *
  468.       **********************************************************************
  469.       }
  470.       pnames[1] := 'farproc1';
  471.       poffsets[1] := Ofs(farproc1);
  472.       pnames[2] := 'farproc2';
  473.       poffsets[2] := Ofs(farproc2);
  474.  
  475.       {restore stack and do a FAR return to the main segment}
  476.       INLINE(
  477.         $8B/$E5/              {mov sp,bp}
  478.         $5D/                  {pop bp}
  479.         $CB                   {ret far}
  480.         );
  481.     END;                      {SetupJumpTable}
  482.  
  483.   PROCEDURE FarCallHandler;
  484.       {-pick up control from a far call and transfer to near procedure}
  485.     CONST
  486.       {following string must be here to allow address to be found from Main Code}
  487.       idstring : BigTurboString = 'FARCALLHANDLER FOLLOWS';
  488.     VAR
  489.       i : Integer;
  490.       procofs : Integer;
  491.       procname : BigTurboString;
  492.     BEGIN
  493.       {get procname from the es:si pointer passed in}
  494.       INLINE(
  495.         $31/$C9/              {XOR    CX,CX}
  496.         $26/                  {ES:    }
  497.         $8A/$0C/              {MOV    CL,[SI]}
  498.         $FE/$C1/              {INC    CL}
  499.         $BF/procname/         {MOV    DI,ofs(procname)}
  500.         $FC/                  {CLD    }
  501.         $26/                  {ES:    }
  502.         $AC/                  {LODSB    }
  503.         $88/$03/              {MOV    [BP+DI],AL}
  504.         $47/                  {INC    DI}
  505.         $E2/$F9               {LOOP    010B}
  506.         );
  507.       {match against the stored procnames}
  508.       i := 0;
  509.       REPEAT
  510.         i := i+1;
  511.       UNTIL (i > MaxNumProcs) OR (pnames[i] = procname);
  512.       {error check}
  513.       IF i > MaxNumProcs THEN BEGIN
  514.         WriteLn(Con);
  515.         WriteLn(Con, 'Far procedure ', procname, ' not found....');
  516.         Halt;
  517.       END;
  518.       {check for stack space, later}
  519.       {call the procedure}
  520.       procofs := poffsets[i];
  521.       INLINE(
  522.         $C4/$46/< procofs/    {LES    AX,procofs[BP]}
  523.         $FF/$D0               {CALL    AX}
  524.         );
  525.  
  526.       {restore stack and FAR return}
  527.       INLINE(
  528.         $8B/$E5/              {mov sp,bp}
  529.         $5D/                  {pop bp}
  530.         $CB                   {ret far}
  531.         );
  532.     END;                      {FarCallHandler}
  533.  
  534. {END OF FAR2.INC}
  535. {****************************************************************************}
  536. {FOLLOWING IS MAINEXAM.PAS}
  537.  
  538.   {$V-}
  539. PROGRAM mainexam;
  540.     {-demonstrate BigTurbo techniques}
  541.  
  542.     {first BigTurbo include file - before anything else}
  543.     {$I main1.inc}
  544.  
  545.     {all your global variables and declarations are in following file}
  546.     {$I exam.glo}
  547.  
  548.     {your own procedures follow}
  549.  
  550.   PROCEDURE mainproc1;
  551.       {-demonstrate getting to and from the extra segment}
  552.     BEGIN
  553.       MakeLongCall('farproc2');
  554.     END;                      {mainproc1}
  555.  
  556.   PROCEDURE mainproc2;
  557.       {-demonstrate getting to and from the extra segment}
  558.     BEGIN
  559.       WriteLn('got to mainproc2 from far segment');
  560.     END;                      {mainproc1}
  561.  
  562.     {second BigTurbo include file - after all other procedures}
  563.     {$I main2.inc}
  564.  
  565.   BEGIN
  566.     {load far code}
  567.     LoadFarCode('farexam.com');
  568.  
  569.     {your code follows}
  570.     WriteLn('in main program');
  571.     WriteLn('calling local procedure mainproc1');
  572.     mainproc1;
  573.     WriteLn('back from mainproc1');
  574.  
  575.   END.
  576.  
  577. {END OF MAINEXAM.PAS}
  578. {****************************************************************************}
  579. {FOLLOWING IS FAREXAM.PAS}
  580.  
  581.   {$V-}
  582. PROGRAM farexam;
  583.     {-demonstrate BigTurbo techniques}
  584.     {this file holds code for the extra segment}
  585.  
  586.     {first BigTurbo include file - before everything else}
  587.     {$I far1.inc}
  588.  
  589.     {all your global variables and declarations are in following file}
  590.     {$I exam.glo}
  591.  
  592.     {your procedures follow}
  593.  
  594.   PROCEDURE farproc1;
  595.       {-demonstrate a local call in the extra segment}
  596.     BEGIN
  597.       WriteLn('got to farproc1');
  598.       WriteLn('calling mainproc2 in main code segment');
  599.       MakeLongCall('mainproc2');
  600.       WriteLn('back from mainproc2');
  601.     END;                      {farproc1}
  602.  
  603.   PROCEDURE farproc2;
  604.       {-just demonstrate getting here from main segment}
  605.     BEGIN
  606.       WriteLn('got to farproc2 from main code');
  607.       WriteLn('calling local procedure farproc1 in far code');
  608.       farproc1;
  609.       WriteLn('returned from farproc1');
  610.     END;                      {farproc2}
  611.  
  612.     {second BigTurbo include file - after all your procedures}
  613.     {$I far2.inc}
  614.  
  615.   BEGIN
  616.     {this block should normally be empty}
  617.     {you can use it to directly call procedures in this program during debugging}
  618.   END.
  619.  
  620.  
  621. {END OF FAREXAM.PAS}
  622. {****************************************************************************}
  623. {FOLLOWING IS EXAM.GLO}
  624.  
  625.     {global definitions and declarations go here}
  626.     {example doesn't need any, so these are bogus}
  627.   TYPE
  628.     xxx = Integer;
  629.   VAR
  630.     i : xxx;
  631.  
  632. {END OF EXAM.GLO}
  633. {****************************************************************************}
  634. ger;
  635.   VAR
  636.     i : xxx;
  637.  
  638. {END OF EXAM.GLO}
  639. {***************************